﻿#pragma once

//using namespace System;
//using namespace System::Runtime::InteropServices;
#include "ftd2xx.h"
#include "LibFT4222.h"

namespace FT4222 {

    public enum class Ft_STATUS : UINT
    {
        FT_OK,
        FT_INVALID_HANDLE,
        FT_DEVICE_NOT_FOUND,
        FT_DEVICE_NOT_OPENED,
        FT_IO_ERROR,
        FT_INSUFFICIENT_RESOURCES,
        FT_INVALID_PARAMETER,
        FT_INVALID_BAUD_RATE,

        FT_DEVICE_NOT_OPENED_FOR_ERASE,
        FT_DEVICE_NOT_OPENED_FOR_WRITE,
        FT_FAILED_TO_WRITE_DEVICE,
        FT_EEPROM_READ_FAILED,
        FT_EEPROM_WRITE_FAILED,
        FT_EEPROM_ERASE_FAILED,
        FT_EEPROM_NOT_PRESENT,
        FT_EEPROM_NOT_PROGRAMMED,
        FT_INVALID_ARGS,
        FT_NOT_SUPPORTED,
        FT_OTHER_ERROR,
        FT_DEVICE_LIST_NOT_READY,
    };

    //FT_OpenEx Flags
    public enum class Ft_OpenFlag : uint32 {
        Ft_OPEN_BY_SERIAL_NUMBER = 1,
        Ft_OPEN_BY_DESCRIPTION = 2,
        Ft_OPEN_BY_LOCATION = 4
    };

    //
    // FT4222 Device status
    //
    public enum class Ft4222_STATUS : UINT
    {
        FT4222_OK,
        FT4222_INVALID_HANDLE,
        FT4222_DEVICE_NOT_FOUND,
        FT4222_DEVICE_NOT_OPENED,
        FT4222_IO_ERROR,
        FT4222_INSUFFICIENT_RESOURCES,
        FT4222_INVALID_PARAMETER,
        FT4222_INVALID_BAUD_RATE,
        FT4222_DEVICE_NOT_OPENED_FOR_ERASE,
        FT4222_DEVICE_NOT_OPENED_FOR_WRITE,
        FT4222_FAILED_TO_WRITE_DEVICE,
        FT4222_EEPROM_READ_FAILED,
        FT4222_EEPROM_WRITE_FAILED,
        FT4222_EEPROM_ERASE_FAILED,
        FT4222_EEPROM_NOT_PRESENT,
        FT4222_EEPROM_NOT_PROGRAMMED,
        FT4222_INVALID_ARGS,
        FT4222_NOT_SUPPORTED,
        FT4222_OTHER_ERROR,
        FT4222_DEVICE_LIST_NOT_READY,

        FT4222_DEVICE_NOT_SUPPORTED = 1000,        // FT_STATUS extending message
        FT4222_CLK_NOT_SUPPORTED,
        FT4222_VENDER_CMD_NOT_SUPPORTED,
        FT4222_IS_NOT_SPI_MODE,
        FT4222_IS_NOT_I2C_MODE,
        FT4222_IS_NOT_SPI_SINGLE_MODE,
        FT4222_IS_NOT_SPI_MULTI_MODE,
        FT4222_WRONG_I2C_ADDR,
        FT4222_INVAILD_FUNCTION,
        FT4222_INVALID_POINTER,
        FT4222_EXCEEDED_MAX_TRANSFER_SIZE,
        FT4222_FAILED_TO_READ_DEVICE,
        FT4222_I2C_NOT_SUPPORTED_IN_THIS_MODE,
        FT4222_GPIO_NOT_SUPPORTED_IN_THIS_MODE,
        FT4222_GPIO_EXCEEDED_MAX_PORTNUM,
        FT4222_GPIO_WRITE_NOT_SUPPORTED,
        FT4222_GPIO_PULLUP_INVALID_IN_INPUTMODE,
        FT4222_GPIO_PULLDOWN_INVALID_IN_INPUTMODE,
        FT4222_GPIO_OPENDRAIN_INVALID_IN_OUTPUTMODE,
        FT4222_INTERRUPT_NOT_SUPPORTED,
        FT4222_GPIO_INPUT_NOT_SUPPORTED,
        FT4222_EVENT_NOT_SUPPORTED,
        FT4222_FUN_NOT_SUPPORT,
    };

    public enum class Ft_DEVICE : UINT 
    {
        FT_DEVICE_BM,
        FT_DEVICE_AM,
        FT_DEVICE_100AX,
        FT_DEVICE_UNKNOWN,
        FT_DEVICE_2232C,
        FT_DEVICE_232R,
        FT_DEVICE_2232H,
        FT_DEVICE_4232H,
        FT_DEVICE_232H,
        FT_DEVICE_X_SERIES,
        FT_DEVICE_4222H_0,
        FT_DEVICE_4222H_1_2,
        FT_DEVICE_4222H_3,
        FT_DEVICE_4222_PROG,
        FT_DEVICE_900,
        FT_DEVICE_930,
        FT_DEVICE_UMFTPD3A,
        FT_DEVICE_2233HP,
        FT_DEVICE_4233HP,
        FT_DEVICE_2232HP,
        FT_DEVICE_4232HP,
        FT_DEVICE_233HP,
        FT_DEVICE_232HP,
        FT_DEVICE_2232HA,
        FT_DEVICE_4232HA,
        FT_DEVICE_232RN,
    };

    public enum class Ft4222_ClockRate:UINT
    {
        SYS_CLK_60 = 0,
        SYS_CLK_24,
        SYS_CLK_48,
        SYS_CLK_80,

    };

    public enum class Ft4222_FUNCTION:UINT
    {
        FT4222_I2C_MASTER = 1,
        FT4222_I2C_SLAVE,
        FT4222_SPI_MASTER,
        FT4222_SPI_SLAVE,

    };

    public enum class Ft4222_SPIMode : UINT
    {
        SPI_IO_NONE = 0,
        SPI_IO_SINGLE = 1,
        SPI_IO_DUAL = 2,
        SPI_IO_QUAD = 4,

    };

    public enum class Ft4222_SPIClock
    {
        CLK_NONE = 0,
        CLK_DIV_2,      // 1/2   System Clock
        CLK_DIV_4,      // 1/4   System Clock
        CLK_DIV_8,      // 1/8   System Clock
        CLK_DIV_16,     // 1/16  System Clock
        CLK_DIV_32,     // 1/32  System Clock
        CLK_DIV_64,     // 1/64  System Clock
        CLK_DIV_128,    // 1/128 System Clock
        CLK_DIV_256,    // 1/256 System Clock
        CLK_DIV_512,    // 1/512 System Clock

    };
    
    //SPI 最终传输时钟
    public enum class Ft4222_SPITransferClock
    {
        SPI234_37KHz,
        SPI312_5KHz,
        SPI375KHz,
        SPI468_75KHz,
        SPI625KHz,
        SPI750KHz,
        SPI937_5KHz,
        SPI1_25MHz,
        SPI1_5MHz,
        SPI1_875MHz,
        SPI2_5MHz,
        SPI3MHz,
        SPI3_75MHz,
        SPI6MHz,
        SPI10MHz,
        SPI20MHz
    };

    public enum class Ft4222_SPICPOL
    {
        CLK_IDLE_LOW = 0,
        CLK_IDLE_HIGH = 1,
    };

    public enum class Ft4222_SPICPHA
    {
        CLK_LEADING = 0,
        CLK_TRAILING = 1,
    };

    public enum class Ft4222_SpiSsoMap : uint8
    {
        SS0O = 0,
        SS1O = 1,
        SS2O = 2,
        SS3O = 3,
    };

    public enum class Spi_DrivingStrength
    {
        DS_4MA = 0,
        DS_8MA,
        DS_12MA,
        DS_16MA,
    };


    public enum class Spi_ChipSelect
    {
        CS_ACTIVE_LOW = 0,
        CS_ACTIVE_HIGH,
    };



    public enum class Gpio_Port
    {
        GPIO_PORT0 = 0,
        GPIO_PORT1,
        GPIO_PORT2,
        GPIO_PORT3
    };

    public enum class Gpio_Dir
    {
        GPIO_OUTPUT = 0,
        GPIO_INPUT,
    };

    public enum class Gpio_Trigger
    {
        GPIO_TRIGGER_RISING = 0x01,
        GPIO_TRIGGER_FALLING = 0x02,
        GPIO_TRIGGER_LEVEL_HIGH = 0x04,
        GPIO_TRIGGER_LEVEL_LOW = 0X08
    };


    public enum class Gpio_Output
    {
        GPIO_OUTPUT_LOW,
        GPIO_OUTPUT_HIGH
    };


    public enum class I2c_MasterFlag
    {
        NONE = 0x80,
        START = 0x02,
        Repeated_START = 0x03,     // Repeated_START will not send master code in HS mode
        STOP = 0x04,
        START_AND_STOP = 0x06,      // START condition followed by SEND and STOP condition
    };


    public enum class Spi_SlaveProtocol
    {
        SPI_SLAVE_WITH_PROTOCOL = 0,
        SPI_SLAVE_NO_PROTOCOL,
        SPI_SLAVE_NO_ACK,
    };

    public value struct Ft4222_Version
    {
        uint32 chipVersion;
        uint32 dllVersion;
    };

    [System::Runtime::InteropServices::StructLayout(System::Runtime::InteropServices::LayoutKind::Sequential, Pack = 1)]
    public ref struct SPI_Slave_Header
    {
        byte syncWord;
        byte cmd;
        byte sn;
        uint16 size;
    };





    public ref class FTBase {
    public:
        static const UINT Ft4222_EVENT_RXCHAR = 8;

        //// spi slave sync word
        static const UINT Ft4222_SPI_SLAVE_SYNC_WORD = 0x5A;

        // spi slave cmd
        static const UINT Ft_SPI_MASTER_TRANSFER = 0x80;
        static const UINT Ft_SPI_SLAVE_TRANSFER = 0x81;
        static const UINT Ft_SPI_SHORT_MASTER_TRANSFER = 0x82;
        static const UINT Ft_SPI_SHORT_SLAVE_TRANSFER = 0x83;
        // Backwards compatibility for typo in earlier version
        static const UINT Ft_SPI_SHART_SLAVE_TRANSFER = 0x83;
        static const UINT Ft_SPI_ACK = 0x84;

    protected:
        FT_HANDLE ftHandle;
    public:
        FTBase();
        ~FTBase();

        static Ft_STATUS Ft_CreateDeviceInfoList([System::Runtime::InteropServices::Out] uint32% lpdwNumDevs);
        static Ft_STATUS Ft_GetDeviceInfoDetail(uint32 dwIndex,
            [System::Runtime::InteropServices::Out] uint32% lpdwFlags,
            [System::Runtime::InteropServices::Out] Ft_DEVICE% lpdwType,
            [System::Runtime::InteropServices::Out] uint32% lpdwID,
            [System::Runtime::InteropServices::Out] uint32% lpdwLocId,
            [System::Runtime::InteropServices::Out] System::String^% serialNumber,
            [System::Runtime::InteropServices::Out] System::String^% description);
        Ft_STATUS Ft_OpenEx(System::IntPtr pArg1, Ft_OpenFlag flags);
        Ft_STATUS Ft_OpenEx(uint32 locId);
        Ft_STATUS Ft_OpenEx(System::String^ serialNumber);
        Ft_STATUS Ft_Close();
        bool Ft_IsOpen();


        Ft4222_STATUS Ft4222_UnInitialize();
        Ft4222_STATUS Ft4222_SetClock(Ft4222_ClockRate clk);
        Ft4222_STATUS Ft4222_GetClock([System::Runtime::InteropServices::Out] Ft4222_ClockRate% clk);
        Ft4222_STATUS Ft4222_SetWakeUpInterrupt(bool enable);
        Ft4222_STATUS Ft4222_SetInterruptTrigger(Gpio_Trigger trigger);
        Ft4222_STATUS Ft4222_SetSuspendOut(bool enable);
        Ft4222_STATUS Ft4222_GetMaxTransferSize([System::Runtime::InteropServices::Out] uint16% pMaxSize);
        Ft4222_STATUS Ft4222_SetEventNotification(uint32 mask, System::IntPtr param);
        Ft4222_STATUS Ft4222_GetVersion([System::Runtime::InteropServices::Out] Ft4222_Version% pVersion);
        Ft4222_STATUS Ft4222_GetChipMode([System::Runtime::InteropServices::Out] byte% pChipMode);
        Ft4222_STATUS Ft4222_ChipReset();


        /* I2C Master Controller Status
         *   bit 0 = controller busy: all other status bits invalid
         *   bit 1 = error condition
         *   bit 2 = slave address was not acknowledged during last operation
         *   bit 3 = data not acknowledged during last operation
         *   bit 4 = arbitration lost during last operation
         *   bit 5 = controller idle
         *   bit 6 = bus busy
         */
        static bool I2cm_CONTROLLER_BUSY(byte status) { return (status & 0x01) != 0; }
        static bool I2cm_DATA_NACK(byte status) { return (status & 0x0A) != 0; }
        static bool I2cm_ADDRESS_NACK(byte status) { return (status & 0x06) != 0; }
        static bool I2cm_ARB_LOST(byte status) { return (status & 0x12) != 0; }
        static bool I2cm_IDLE(byte status) { return (status & 0x20) != 0; }
        static bool I2cm_BUS_BUSY(byte status) { return (status & 0x40) != 0; }
    };


    public ref class SPI : public FTBase
	{
    public:
        SPI();
        ~SPI();

        Ft4222_STATUS Ft4222_SPIMaster_Init(Ft4222_SPIMode  ioLine, Ft4222_SPIClock clock, Ft4222_SPICPOL  cpol, Ft4222_SPICPHA  cpha, Ft4222_SpiSsoMap ssoMap);
        Ft4222_STATUS Ft4222_SPIMaster_SetMode(Ft4222_SPICPOL  cpol, Ft4222_SPICPHA  cpha);
        Ft4222_STATUS Ft4222_SPIMaster_SetCS(Spi_ChipSelect cs);
        Ft4222_STATUS Ft4222_SPIMaster_SetLines(Ft4222_SPIMode spiMode);
        Ft4222_STATUS Ft4222_SPIMaster_SingleRead(array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeOfRead, bool isEndTransaction);
        Ft4222_STATUS Ft4222_SPIMaster_SingleWrite(array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred, bool isEndTransaction);
        Ft4222_STATUS Ft4222_SPIMaster_SingleReadWrite(array<byte>^ readBuffer, array<byte>^ writeBuffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred, bool isEndTransaction);
        Ft4222_STATUS Ft4222_SPIMaster_MultiReadWrite(array<byte>^ readBuffer, array<byte>^ writeBuffer, uint8 singleWriteBytes, uint16 multiWriteBytes, uint16 multiReadBytes, [System::Runtime::InteropServices::Out] uint32% sizeOfRead);

        Ft4222_STATUS Ft4222_SPISlave_Init();
        Ft4222_STATUS Ft4222_SPISlave_InitEx(Spi_SlaveProtocol protocolOpt);
        Ft4222_STATUS Ft4222_SPISlave_SetMode(Ft4222_SPICPOL  cpol, Ft4222_SPICPHA  cpha);
        Ft4222_STATUS Ft4222_SPISlave_GetRxStatus([System::Runtime::InteropServices::Out] uint16% pRxSize);
        Ft4222_STATUS Ft4222_SPISlave_Read(array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeOfRead);
        Ft4222_STATUS Ft4222_SPISlave_Write(array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred);

        Ft4222_STATUS Ft4222_SPI_Reset();
        Ft4222_STATUS Ft4222_SPI_ResetTransaction(byte spiIdx);
        Ft4222_STATUS Ft4222_SPI_SetDrivingStrength(Spi_DrivingStrength clkStrength, Spi_DrivingStrength ioStrength, Spi_DrivingStrength ssoStrength);

        static Ft4222_STATUS SpiClockToSystemClock(Ft4222_SPITransferClock trClock,
            [System::Runtime::InteropServices::Out] Ft4222_ClockRate% sysClock,
            [System::Runtime::InteropServices::Out] Ft4222_SPIClock% spiDiv);
    };

    public ref class I2C : public FTBase
    {
    public:
        I2C();
        ~I2C();

        static const uint8 Ft4222_I2CRW_Start = 0x02;
        static const uint8 Ft4222_I2CRW_RStart = 0x03;
        static const uint8 Ft4222_I2CRW_Stop = 0x04;
        static const uint8 Ft4222_I2CRW_StartAndStop = 0x06;


        Ft4222_STATUS Ft4222_I2CMaster_Init(uint32 kbps);
        Ft4222_STATUS Ft4222_I2CMaster_Read(uint16 deviceAddress, array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred);
        Ft4222_STATUS Ft4222_I2CMaster_Write(uint16 deviceAddress, array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred);
        Ft4222_STATUS Ft4222_I2CMaster_ReadEx(uint16 deviceAddress, uint8 flag, array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred);
        Ft4222_STATUS Ft4222_I2CMaster_WriteEx(uint16 deviceAddress, uint8 flag, array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred);
        Ft4222_STATUS Ft4222_I2CMaster_Reset();
        Ft4222_STATUS Ft4222_I2CMaster_GetStatus([System::Runtime::InteropServices::Out] byte% controllerStatus);
        Ft4222_STATUS Ft4222_I2CMaster_ResetBus();

        Ft4222_STATUS Ft4222_I2CSlave_Init();
        Ft4222_STATUS Ft4222_I2CSlave_Reset();
        Ft4222_STATUS Ft4222_I2CSlave_GetAddress([System::Runtime::InteropServices::Out] byte% addr);
        Ft4222_STATUS Ft4222_I2CSlave_SetAddress(byte addr);
        Ft4222_STATUS Ft4222_I2CSlave_GetRxStatus([System::Runtime::InteropServices::Out] uint16% pRxSize);
        Ft4222_STATUS Ft4222_I2CSlave_Read(array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred);
        Ft4222_STATUS Ft4222_I2CSlave_Write(array<byte>^ buffer, uint16 bufferSize, [System::Runtime::InteropServices::Out] uint16% sizeTransferred);
        Ft4222_STATUS Ft4222_I2CSlave_SetClockStretch(bool enable);
        Ft4222_STATUS Ft4222_I2CSlave_SetRespWord(byte responseWord);

    };

    public ref class GPIO : public FTBase
    {
    public:
        GPIO();
        ~GPIO();

        Ft4222_STATUS Ft4222_GPIO_Init(array<Gpio_Dir>^ gpioDir_1_2_3_4);
        Ft4222_STATUS Ft4222_GPIO_Read(Gpio_Port portNum, [System::Runtime::InteropServices::Out] bool% high);
        Ft4222_STATUS Ft4222_GPIO_Write(Gpio_Port portNum, bool high);
        Ft4222_STATUS Ft4222_GPIO_SetInputTrigger(Gpio_Port portNum, Gpio_Trigger trigger);
        Ft4222_STATUS Ft4222_GPIO_GetTriggerStatus(Gpio_Port portNum, [System::Runtime::InteropServices::Out] uint16% queueSize);
        Ft4222_STATUS Ft4222_GPIO_ReadTriggerQueue(Gpio_Port portNum, array<Gpio_Trigger>^ events, uint16 readSize, [System::Runtime::InteropServices::Out] uint16% sizeofRead);
        Ft4222_STATUS Ft4222_GPIO_SetWaveFormMode(bool enable);
    };




}
